package v1

import (
	"fmt"
	jwtauth "github.com/dgrijalva/jwt-go"
	"github.com/gin-gonic/gin"
	"github.com/go-redis/redis"
	"server/client/jwt"
	"server/config"
	"server/model"
	"server/model/request"
	"server/model/response"
	"server/service"
	"server/utils"
	"time"
)

func Login(c *gin.Context) {
	var L request.Login
	_ = c.ShouldBindJSON(&L)
	if err := utils.Verify(L, utils.LoginVerify); err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}

	U := &model.SysUser{Username: L.Username, Password: L.Password}
	if err, user := service.Login(U); err != nil {
		fmt.Printf("登陆失败! 用户名不存在或者密码错误 err is %v\n", err)
		response.FailWithMessage("用户名不存在或者密码错误", c)
	} else {
		issueToken(c, user)
	}
}

func issueToken(c *gin.Context, user *model.SysUser) {
	//颁发token,生成新token,并更新缓存
	j := jwt.JwtClient
	claims := &jwt.JwtClaims{
		UUID:       user.UUID,
		ID:         user.ID,
		NickName:   user.NickName,
		Username:   user.Username,
		RoleId:     user.RoleId,
		BufferTime: 60 * 60 * 24, // 缓冲时间1天 缓冲时间内会获得新的token刷新令牌 此时一个用户会存在两个有效令牌 但是前端只留一个 另一个会丢失
		StandardClaims: jwtauth.StandardClaims{
			NotBefore: time.Now().Unix() - 1000,       // 签名生效时间
			ExpiresAt: time.Now().Unix() + 60*60*24*7, // 过期时间 7天
			Issuer:    "jwt-server",                   // 签名的发行者
		},
	}
	token, err := j.CreateToken(claims)
	if err != nil {
		fmt.Printf("获取token失败 err %v", err)
		response.FailWithMessage("获取token失败", c)
		return
	}
	if !config.GlobalConf.System.UseMultipoint {
		response.OkWithDetailed(response.LoginResponse{
			User:      user,
			Token:     token,
			ExpiresAt: claims.StandardClaims.ExpiresAt * 1000,
		}, "登录成功", c)
		return
	}
	//判断当前用户是否已经登陆，缓存中有token
	if err, jwtStr := service.GetRedisJWT(user.Username); err == redis.Nil {
		//首次登陆设置缓存
		if err := service.SetRedisJWT(token, user.Username); err != nil {
			fmt.Printf("设置登录状态失败 err %v", err)
			response.FailWithMessage("设置登录状态失败", c)
			return
		}
		response.OkWithDetailed(response.LoginResponse{
			User:      user,
			Token:     token,
			ExpiresAt: claims.StandardClaims.ExpiresAt * 1000,
		}, "登录成功", c)
	} else if err != nil {
		//操作redis失败
		fmt.Printf("设置登录状态失败 err %v", err)
		response.FailWithMessage("设置登录状态失败", c)
	} else {
		//将老缓存中的token设置为黑名单
		var blackJWT model.Blacklist
		blackJWT.Jwt = jwtStr
		if err := service.SetBlacklist(blackJWT); err != nil {
			response.FailWithMessage("jwt作废失败", c)
			return
		}
		if err := service.SetRedisJWT(token, user.Username); err != nil {
			response.FailWithMessage("设置登录状态失败", c)
			return
		}
		response.OkWithDetailed(response.LoginResponse{
			User:      user,
			Token:     token,
			ExpiresAt: claims.StandardClaims.ExpiresAt * 1000,
		}, "登录成功", c)
	}

}

func Register(c *gin.Context) {
	var R request.Register
	_ = c.ShouldBindJSON(&R)
	if err := utils.Verify(R, utils.RegisterVerify); err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	user := &model.SysUser{Username: R.Username, NickName: R.NickName, Password: R.Password, RoleId: R.RoleId}
	err, userReturn := service.Register(*user)
	if err != nil {
		fmt.Printf("注册失败,error is %v\n", err)
		response.FailWithDetailed(response.SysUserResponse{User: userReturn}, "注册失败", c)
	} else {
		response.OkWithDetailed(response.SysUserResponse{User: userReturn}, "注册成功", c)
	}
}

func GetUserList(c *gin.Context) {
	var pageInfo request.PageInfo
	_ = c.BindQuery(&pageInfo)

	if err := utils.Verify(pageInfo, utils.PageInfoVerify); err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	if err, list, total := service.GetUserInfoList(pageInfo); err != nil {
		fmt.Printf("获取失败 err %v", err)
		response.FailWithMessage("获取失败", c)
	} else {
		response.OkWithDetailed(response.PageResult{
			List:     list,
			Total:    total,
			Page:     pageInfo.Page,
			PageSize: pageInfo.PageSize,
		}, "获取成功", c)
	}
}

func GetUserInfo(c *gin.Context) {
	userID := c.Param("id")

	if err, u := service.FindUserByUuid(userID); err != nil {
		fmt.Printf("查询失败 %v", err)
		response.FailWithMessage("查询失败，找不到当前用户", c)
	} else {
		response.OkWithData(u, c)
	}

}
func ChangePassword(c *gin.Context) {
	var user request.ChangePasswordStruct
	_ = c.ShouldBindJSON(&user)
	if err := utils.Verify(user, utils.ChangePasswordVerify); err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	U := &model.SysUser{Username: user.Username, Password: user.Password}
	if err, _ := service.ChangePassword(U, user.NewPassword); err != nil {
		fmt.Printf("修改失败 %v", err)
		response.FailWithMessage("修改失败，原密码与当前账户不符", c)
	} else {
		response.OkWithMessage("修改成功", c)
	}
}

func DeleteUser(c *gin.Context) {
	userID := c.Param("id")

	jwtId := getCurrentUserID(c)
	if jwtId != userID {
		response.FailWithMessage("删除失败, token不是自己的", c)
		return
	}
	if err := service.DeleteUser(userID); err != nil {
		fmt.Printf("删除失败 %v", err)
		response.FailWithMessage("删除失败", c)
	} else {
		response.OkWithMessage("删除成功", c)
	}
}
func getCurrentUserID(c *gin.Context) string {
	if claims, exists := c.Get("claims"); !exists {
		fmt.Println("从Gin的Context中获取从jwt解析出来的用户ID失败, 请检查路由是否使用jwt中间件")
		return ""
	} else {
		waitUse := claims.(*jwt.JwtClaims)
		return waitUse.UUID
	}
}

func ChangeUserRole(c *gin.Context) {
	var user request.SetUserAuth
	_ = c.ShouldBindJSON(&user)
	if err := utils.Verify(user, utils.SetUserAuthorityVerify); err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	//需要验证roleID是否合法
	if err, _ := service.FindRoleById(user.RoleId); err != nil {
		response.FailWithDetailed(err.Error(),"roleId 不存在",c)
		return
	}

	if err := service.ChangeUserRole(user.UUID, user.RoleId); err != nil {
		fmt.Printf("修改失败 %v", err)
		response.FailWithMessage("修改失败", c)
	} else {
		response.OkWithMessage("修改成功", c)
	}
}
